﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"
#include "StarrySkyInputConfig.h"
#include "StarrySkyInputComponent.generated.h"


UCLASS()
class STARRYSKY_API UStarrySkyInputComponent : public UEnhancedInputComponent
{
	GENERATED_BODY()

public:
	//绑定按下，释放，按住操作
	/**
	 * 定义了一个模版函数，用于绑定输入动作
	 * class UserClass：表示任意一个类类型。在这里，class 和 typename 关键字作用相同，都用来声明一个模板类型参数。
	 * typename PressedFuncType：表示任意一个类型，通常用于指定函数指针、成员函数指针或者可调用对象（如 lambda 表达式）的类型。
	 * 这个模板的作用是为了让 BindAbilityActions 函数可以适用于不同的类和对应的函数类型，从而实现灵活地绑定按键操作（按下、释放、按住）到具体的处理逻辑上。
	 * 这里的 typename 用于声明模板类型参数，表示这些参数将是某种类型。虽然此处用 class 替代 typename 效果相同，但使用 typename 更能体现这些参数代表的是函数类型而非类实例
	 * typename：
	 * 模板参数声明
	 *	在模板定义中声明类型参数，与 class 关键字作用相同
	 *	例如：template<typename T> 和 template<class T> 是等价的
	 *依赖作用域中的类型标识
	 *	告诉编译器某个嵌套名称是类型而不是变量或函数
	 *	例如：typename MyClass<T>::iterator iter;
	 */
	template<class UserClass, typename PressedFuncType, typename releasedFuncType, typename HeldFuncType>
	void BindAbilityActions(const UStarrySkyInputConfig* InputConfig,UserClass* Object, PressedFuncType PressedFunc, releasedFuncType releasedFunc, HeldFuncType HeldFunc);
protected:
};

template <class UserClass, typename PressedFuncType, typename releasedFuncType, typename HeldFuncType>
void UStarrySkyInputComponent::BindAbilityActions(const UStarrySkyInputConfig* InputConfig, UserClass* Object,
	PressedFuncType PressedFunc, releasedFuncType releasedFunc, HeldFuncType HeldFunc)
{
	//首先判断InputConfig是否有效
	check(InputConfig);
	//循环StarrySkyInputConfig资产数据中所有添加的输入操作，根据按下的输入方法绑定所有输入到不同的方法中，把传入的回调函数指针绑定到不同的输入中
	//相当于灵活的将所有StarrySkyInputConfig注册的输入绑定到对应的方法中，最后添加的Action.InputTag一个参数数组，可以将多个参数传递到回调函数进行接收
	for (const FStarrySkyInputAction& Action : InputConfig->AbilityInputActions)
	{
		//循环游戏标签和输入操作列表
		if (Action.InputAction && Action.InputTag.IsValid())
		{
			//判断按下操作的函数是否有效
			if(PressedFunc)
			{
				BindAction(Action.InputAction, ETriggerEvent::Started, Object, PressedFunc,Action.InputTag);
			}
			//判断释放操作的函数是否有效
			if(releasedFunc)
			{
				BindAction(Action.InputAction, ETriggerEvent::Completed, Object, releasedFunc,Action.InputTag);
			}
			//判断按住操作的函数是否有效
			if(HeldFunc)
			{
				BindAction(Action.InputAction, ETriggerEvent::Triggered, Object, HeldFunc,Action.InputTag);
			}
		}
	}
}
